package com.kgd.news.wxpay.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.kgd.news.utils.StringUtilsWx;
import com.kgd.news.utils.wx.WxHelper;
import com.kgd.news.wxpay.constant.Constant;
import com.kgd.news.wxpay.entity.PayInfo;
import com.kgd.news.wxpay.util.*;
import org.apache.log4j.Logger;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class PayControllerUtil {
    private static Logger log = Logger.getLogger(PayControllerUtil.class);

    public static String prePay(String openId, HttpServletRequest request, int moneyNum, int hb_num,String randomOrderId) {
        String content = null;
        Map map = new HashMap();
        ObjectMapper mapper = new ObjectMapper();
        boolean result = false;
        String info = "";
        log.error("\n======================================================");
        log.error("openid: " + openId);
        if(StringUtilsWx.isEmpty(openId)) {
            result = false;
            info = "获取到openId为空";
        } else {
            openId = openId.replace("\"", "").trim();
            String clientIP = CommonUtil.getClientIp(request);
            log.error("openId: " + openId + ", clientIP: " + clientIP);
            Long timeStamp = System.currentTimeMillis() / 1000;
            map.put("timeStamp", timeStamp + "");
            String nonce_str = RandomUtils.generateMixString(32);
            String prepayId = unifiedOrder(openId, clientIP, nonce_str,moneyNum,hb_num,randomOrderId);
            String stringSignTemp = "appId=" + WxHelper.getAppId() + "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepayId + "&signType=MD5&timeStamp=" + timeStamp;
            //再次签名，这个签名用于小程序端调用wx.requesetPayment方法
//            WxPayConfig.key
            String paySign = PayUtils.sign(stringSignTemp, Constant.APP_KEY, "utf-8").toUpperCase();
            map.put("appid", WxHelper.getAppId());
            map.put("paySign", paySign);
            log.error("prepayId: " + prepayId);
            log.error("paySign: " + paySign);
            if(StringUtilsWx.isEmpty(prepayId)) {
                result = false;
                info = "出错了，未获取到prepayId";
            } else {
                result=true;
                map.put("package", "prepay_id=" + prepayId);
                map.put("signType", "MD5");
                map.put("nonceStr", nonce_str);
                map.put("orderid", randomOrderId);
            }
        }
        try {
            map.put("result", result);
            map.put("info", info);
            content = mapper.writeValueAsString(map);
            log.error("prepayreturn: " + content);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return content;
    }



    /**
     * 调用统一下单接口
     * @param openId
     * @param moneyNum
     * @param hb_num
     */
    private static String unifiedOrder(String openId, String clientIP, String randomNonceStr, int moneyNum, int hb_num,String randomOrderId) {
        try {
            String url = Constant.URL_UNIFIED_ORDER;
            PayInfo payInfo = createPayInfo(openId, clientIP, randomNonceStr,moneyNum,randomOrderId);
            String md5 = getSign(payInfo);
            payInfo.setSign(md5);
            log.error("md5 value: " + md5);
            String xml = CommonUtil.payInfoToXML(payInfo);
            xml = xml.replace("__", "_").replace("<![CDATA[1]]>", "1");
            //xml = xml.replace("__", "_").replace("<![CDATA[", "").replace("]]>", "");
            log.error(xml);
//            xml = new String(xml.toString().getBytes(), "ISO8859-1");
            StringBuffer buffer = HttpUtil.httpsRequest(url, "POST", xml);

            log.error("unifiedOrder request return body: \n" + buffer.toString());
            Map<String, String> result = CommonUtil.parseXml(buffer.toString());
            String return_code = result.get("return_code");
            if(!StringUtilsWx.isEmpty(return_code) && return_code.equals("SUCCESS")) {
                String result_code = result.get("result_code");
                if(!StringUtilsWx.isEmpty(result_code) && !result_code.equals("SUCCESS")) {
                    log.error("统一下单错误！");
                    return "";
                }
                String prepay_Id = result.get("prepay_id");
                return prepay_Id;
            } else {
                return "";
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return "";
    }

    public static PayInfo createPayInfo(String openId, String clientIP, String randomNonceStr, int moneyNum, String randomOrderId) {

        Date date = new Date();
        String timeStart = TimeUtils.getFormatTime(date, Constant.TIME_FORMAT);
        String timeExpire = TimeUtils.getFormatTime(TimeUtils.addDay(date, Constant.TIME_EXPIRE), Constant.TIME_FORMAT);
//        时间戳+随机数
//        这个就是商户订单号
        PayInfo payInfo = new PayInfo();
//        字段名或表名冲突时，可以用`order`括起来
//        Order order= Order.dao.findFirst("select * from `order` where orderid = ? ",randomOrderId);
//        if (order != null) {
//            order.setOrdertime(timeStart);
//            order.update();
//        } else {
////            查询不到订单表
//            return payInfo;
//        }
        payInfo.setAppid(WxHelper.getAppId());
        payInfo.setMch_id(Constant.MCH_ID);
        payInfo.setDevice_info("WEB");
        payInfo.setNonce_str(randomNonceStr);
        payInfo.setSign_type("MD5");  //默认即为MD5
//        商品简单描述，该字段请按照规范传递，具体请见https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=4_2
//        payInfo.setBody("HBPAYMENT");
        payInfo.setBody(Constant.HB_DESC);
        payInfo.setAttach("zhifucesh4luluteam");
        payInfo.setOut_trade_no(randomOrderId);
        payInfo.setTotal_fee(moneyNum);
        payInfo.setSpbill_create_ip(clientIP);
        payInfo.setTime_start(timeStart);
        payInfo.setTime_expire(timeExpire);
        payInfo.setNotify_url(Constant.URL_NOTIFY);
        payInfo.setTrade_type("JSAPI");
        payInfo.setLimit_pay("no_credit");
        payInfo.setOpenid(openId);

        return payInfo;
    }

    public static String getSign(PayInfo payInfo) throws Exception {
        StringBuffer sb = new StringBuffer();
        sb.append("appid=" + payInfo.getAppid())
                .append("&attach=" + payInfo.getAttach())
                .append("&body=" + payInfo.getBody())
                .append("&device_info=" + payInfo.getDevice_info())
                .append("&limit_pay=" + payInfo.getLimit_pay())
                .append("&mch_id=" + payInfo.getMch_id())
                .append("&nonce_str=" + payInfo.getNonce_str())
                .append("&notify_url=" + payInfo.getNotify_url())
                .append("&openid=" + payInfo.getOpenid())
                .append("&out_trade_no=" + payInfo.getOut_trade_no())
                .append("&sign_type=" + payInfo.getSign_type())
                .append("&spbill_create_ip=" + payInfo.getSpbill_create_ip())
                .append("&time_expire=" + payInfo.getTime_expire())
                .append("&time_start=" + payInfo.getTime_start())
                .append("&total_fee=" + payInfo.getTotal_fee())
                .append("&trade_type=" + payInfo.getTrade_type())
//         APP_KEY是什么
                .append("&key=" + Constant.APP_KEY);

        log.error("排序后的拼接参数：" + sb.toString());

        return  MD5Utils.getMD5(sb.toString().trim() ).toUpperCase();
//        BODY是中文时，下面的md5的方式是不行的
//        return CommonUtil.getMD5(sb.toString().trim()).toUpperCase();
    }

    public static void splitRedVollet(int n,double money) {
//        money总金额
        if (n*1.0/100>money) {    //若每个人不能分至少一分钱，则显示金额太少，结束程序
            System.out.println("钱太少了，多发点给朋友们吧");
            return;
        }
        double[] result  = allocateRedPacket(n,100*money);   //乘以100，把元转换为分
        for (int i = 0; i < result.length; i++) {
            System.out.println(result[i]);
        }
//        保存到数据库
        result.toString();
    }

    private static double[] allocateRedPacket(int n, double money) {
        // TODO Auto-generated method stub
        double[] result  = new double[n];
        double[] randNumber = new double[n];
        double randSum = 0;   //随机数和
        double allocateSum = money-n;    //按每人一分钱的计划扣出来，剩下的再分配
        for (int i = 0; i < randNumber.length; i++) {
            randNumber[i]=Math.random()*allocateSum;    //生成随机数
            randSum+=randNumber[i];
        }
        double left = allocateSum;
        for (int i = 0; i < result.length-1; i++) {
            result[i]=Math.round(randNumber[i]/randSum*allocateSum);
            left -= result[i];
            result[i]=(result[i]+1)*1.0/100;       //把一分钱加回去
        }
        result[n-1] = (left+1)*1.0/100;
        return result;
    }

}


